<template>
    <el-select :style="'width:'+width" :disabled="disabled" :filter-method="filterMethod" :filterable="filterable" :title="multiple? optionData.name : ''" :value="value" @clear="clear" @visible-change="visibleChange" clearable placeholder="请选择" ref="select" size="mini" style="width: 100%;">
        <el-option :label="optionData.name" :value="optionData.id" class="tree-select__option" ref="option">
            <el-tree :class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`" :data="data" :default-expanded-keys="[value]" :expand-on-click-node="multiple" :filter-node-method="filterNode" :highlight-current="!multiple" :node-key="nodeKey" :props="props" :show-checkbox="multiple" @check-change="handleCheckChange" @node-click="handleNodeClick" class="tree-select__tree" ref="tree"></el-tree>
        </el-option>
    </el-select>
</template>
  
  <script>
export default {
    name: 'TreeSelect',
    props: {
        // v-model绑定
        value: {
            type: [String, Number],
            default: null,
        },
        multiple: {
            type: Boolean,
            default: false,
        },
        // 树形的数据
        data: {
            type: Array,
            default: function () {
                return []
            },
        },
        // 每个树节点用来作为唯一标识的属性
        nodeKey: {
            type: [String, Number],
            default: 'id',
        },
        filterable: {
            type: Boolean,
            default: false,
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        width:{
            type: String,
            default: '500px',
        },
        // tree的props配置
        props: {
            type: Object,
            default: function () {
                return {
                    label: 'label',
                    children: 'children',
                }
            },
        },
    },
    data() {
        return {
            optionData: {
                id: '',
                name: '',
            },
            filterFlag: false,
        }
    },
    watch: {
        value: {
            handler(val) {
                if (!this.isEmpty(this.data)) {
                    this.init(val)
                }
            },
            immediate: true,
        },
        data: function (val) {
            if (!this.isEmpty(val)) {
                this.init(this.value)
            }
        },
    },
    created() {},
    methods: {
        // 是否为空
        isEmpty(val) {
            for (let key in val) {
                return false
            }
            return true
        },
        handleNodeClick(data) {
            if (this.multiple) {
                return
            }
            this.$emit('input', data[this.nodeKey])
            this.$refs.select.visible = false
        },
        handleCheckChange() {
            const nodes = this.$refs.tree.getCheckedNodes()
            const value = nodes.map((item) => item[this.nodeKey]).join(',')
            this.$emit('input', value)
        },
        init(val) {
            // 多选
            if (this.multiple) {
                const arr = val.toString().split(',')
                this.$nextTick(() => {
                    this.$refs.tree.setCheckedKeys(arr)
                    const nodes = this.$refs.tree.getCheckedNodes()
                    this.optionData.id = val
                    this.optionData.name = nodes.map((item) => item[this.props.label]).join(',')
                })
            }
            // 单选
            else {
                val = val === '' ? null : val
                this.$nextTick(() => {
                    this.$refs.tree.setCurrentKey(val)
                    if (val === null) {
                        return
                    }
                    const label = this.props.label || 'name'
                    const node = this.$refs.tree.getNode(val)
                    this.optionData.id = val
                    this.optionData[label] = node.label
                })
            }
        },
        visibleChange(e) {
            if (e) {
                const tree = this.$refs.tree
                this.filterFlag && tree.filter('')
                this.filterFlag = false
                let selectDom = null
                if (this.multiple) {
                    selectDom = tree.$el.querySelector('.el-tree-node.is-checked')
                } else {
                    selectDom = tree.$el.querySelector('.is-current')
                }
                setTimeout(() => {
                    this.$refs.select.scrollToOption({ $el: selectDom })
                }, 0)
            }
        },
        clear() {
            this.$emit('input', '')
        },
        filterMethod(val) {
            this.filterFlag = true
            this.$refs.tree.filter(val)
        },
        filterNode(value, data) {
            if (!value) return true
            const label = this.props.label || 'name'
            return data[label].indexOf(value) !== -1
        },
    },
}
</script>
  
  <style lang="scss">
.tree-select__option {
    &.el-select-dropdown__item {
        height: auto;
        line-height: 1;
        padding: 0;
        background-color: #fff;
    }
}

.tree-select__tree {
    padding: 4px 20px;
    font-weight: 400;
    &.tree-select__tree--radio {
        .el-tree-node.is-current > .el-tree-node__content {
            color: #fff;
            font-weight: 700;
        }
    }
}
</style>